﻿using System;
using System.Collections.Generic;
using System.Linq;
using Interfaces.FilterModels;
using Interfaces.Filters;
using Interfaces.Models;

namespace BusinessLogic.Models.Filter.GenericFilters
{
    public class PriceFilter<TPriceData, TFilterModel> : IFilter
        where TPriceData : IPrice
        where TFilterModel : IPriceFilterModel
    {
        private readonly LinkedList<Func<TPriceData, bool>> _filters;

        private readonly TFilterModel _filterModel;

        public PriceFilter(TFilterModel filterModel)
        {
            _filterModel = filterModel;
            _filters = new LinkedList<Func<TPriceData, bool>>();
            Init();
        }

        private void Init()
        {
            _filters.AddLast(GetTradeDateFilter());
            _filters.AddLast(GetBidFilter());
            _filters.AddLast(GetAskFilter());
        }

        public virtual IEnumerable<object> Filtrate(IEnumerable<object> source)
        {
            if (source != null)
            {
                var target = source as IEnumerable<TPriceData>;

                if (target == null)
                    throw new ArgumentException("Source has incorrect type.");

                target = _filters.Aggregate(target, (current, filter) => current.Where(filter));
                return target as IEnumerable<object>;
            }

            return null;
        }

        protected virtual Func<TPriceData, bool> GetTradeDateFilter()
        {
            var lowTradeDate = _filterModel.LowTradeDate ?? DateTime.MinValue;
            var highTradeDate = _filterModel.HighTradeDate ?? DateTime.MaxValue;
            return item => item.TradeDate <= highTradeDate && item.TradeDate >= lowTradeDate;
        }

        protected virtual Func<TPriceData, bool> GetBidFilter()
        {
            var lowBid = _filterModel.LowBid ?? float.MinValue;
            var highBid = _filterModel.HighBid ?? float.MaxValue;
            return item => item.Bid <= highBid && item.Bid >= lowBid;
        }

        protected virtual Func<TPriceData, bool> GetAskFilter()
        {
            var lowAsk = _filterModel.LowAsk ?? float.MinValue;
            var highAsk = _filterModel.HighAsk ?? float.MaxValue;
            return item => item.Ask <= highAsk && item.Bid >= lowAsk;
        }

    }
}
